#ifndef RpcConnection_h__
#define RpcConnection_h__

#include "Connection.h"
#include "PacketParser.h"

#include <google/protobuf/service.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>

#include "../Common/Timer.h"

class RPCClosure : public ::google::protobuf::Closure
{
public:

	static RPCClosure* New(const boost::function0<void>& h)
	{
		return new RPCClosure(h);
	}

	virtual void Run()
	{
		m_h();
		delete this;
	}

private:
	RPCClosure(boost::function0<void> h) : m_h(h) {}
	virtual ~RPCClosure(){}

	boost::function0<void> m_h;
};


class RpcConnectionListener;
typedef boost::shared_ptr<google::protobuf::Service> ServicePtr;

struct ResponseData
{
	ResponseData(google::protobuf::RpcController *ctr,
				const google::protobuf::Message *r,
				google::protobuf::Message * m, 
				google::protobuf::Closure * c) :
		controller(ctr),request(r),response(m), done(c)
		{

		}

	google::protobuf::RpcController *controller;
	const google::protobuf::Message *request;
	google::protobuf::Message * response;
	google::protobuf::Closure *done;
};

class RpcConnection : 
	public Connection,
	public google::protobuf::RpcChannel,
	public google::protobuf::RpcController
{
public:
	explicit RpcConnection(boost::asio::io_service& io_service, 
		ConnectionClosedListener* listerner = NULL);

	virtual ~RpcConnection(void);

	virtual void update(uint32 timeElapse);

	virtual Connection* span(boost::asio::io_service& io_service, ConnectionClosedListener* listerner)
	{
		RpcConnection* rc = new RpcConnection(io_service,listerner);
		return rc;
	}

	void setService(ServicePtr s)
	{
		m_service = s;
	}

	ServicePtr getService() const
	{
		return m_service;
	}

	void CallServiceMethod(google::protobuf::Service*, uint32 method_id, ArrayBuffer& buffer);

	//rpc
public:
	//RpcChannel
	// Call the given method of the remote service.  The signature of this
	// procedure looks the same as Service::CallMethod(), but the requirements
	// are less strict in one important way:  the request and response objects
	// need not be of any specific class as long as their descriptors are
	// method->input_type() and method->output_type().
	virtual void CallMethod(const google::protobuf::MethodDescriptor* method,
		google::protobuf::RpcController* controller,
		const google::protobuf::Message* request,
		google::protobuf::Message* response,
		google::protobuf::Closure* done);

	// Client-side methods ---------------------------------------------
	// These calls may be made from the client side only.  Their results
	// are undefined on the server side (may crash).

	// Resets the RpcController to its initial state so that it may be reused in
	// a new call.  Must not be called while an RPC is in progress.
	virtual void Reset() {}

	// After a call has finished, returns true if the call failed.  The possible
	// reasons for failure depend on the RPC implementation.  Failed() must not
	// be called before a call has finished.  If Failed() returns true, the
	// contents of the response message are undefined.
	virtual bool Failed() const { return isStopped(); }

	// If Failed() is true, returns a human-readable description of the error.
	virtual string ErrorText() const { return ""; }

	// Advises the RPC system that the caller desires that the RPC call be
	// canceled.  The RPC system may cancel it immediately, may wait awhile and
	// then cancel it, or may not even cancel the call at all.  If the call is
	// canceled, the "done" callback will still be called and the RpcController
	// will indicate that the call failed at that time.
	virtual void StartCancel() {}

	// Server-side methods ---------------------------------------------
	// These calls may be made from the server side only.  Their results
	// are undefined on the client side (may crash).

	// Causes Failed() to return true on the client side.  "reason" will be
	// incorporated into the message returned by ErrorText().  If you find
	// you need to return machine-readable information about failures, you
	// should incorporate it into your response protocol buffer and should
	// NOT call SetFailed().
	virtual void SetFailed(const string& reason) {}

	// If true, indicates that the client canceled the RPC, so the server may
	// as well give up on replying to it.  The server should still call the
	// final "done" callback.
	virtual bool IsCanceled() const { return isStopped(); }

	// Asks that the given callback be called when the RPC is canceled.  The
	// callback will always be called exactly once.  If the RPC completes without
	// being canceled, the callback will be called after completion.  If the RPC
	// has already been canceled when NotifyOnCancel() is called, the callback
	// will be called immediately.
	//
	// NotifyOnCancel() must be called no more than once per request.
	virtual void NotifyOnCancel(google::protobuf::Closure* callback) {}

protected:
	virtual bool onReadRawData(uint8* buffer, size_t s);

	void breathe();
	void onHandlePackage(PacketHead& pkh, ArrayBuffer& buffer);

	virtual void onHandleRequest(RequestHead& rh, ArrayBuffer& buffer)
	{
	}

	virtual void onHandleResponse(ResponseHead& rh, ArrayBuffer& buffer)
	{
	}

private:
	Timer m_breathe_timer;
	int m_breather_sendcount;
	int m_breather_recvcount;

	PacketParser package_parser_;

	typedef stdext::hash_map<uint64, ResponseData> ResponseMap;
	ResponseMap m_response_handler;

	ServicePtr m_service;
};

typedef boost::shared_ptr<RpcConnection> RpcConnectionPtr;



#endif // RpcConnection_h__
